package com.allkapps.bbmopenchat.utils;

import java.util.Vector;

/**
 * Thread worker implementation that runs queued objects. The associated thread is not a daemon thread and is not long-running. If
 * the thread has finished, it will be restarted when a task is added to the queue.
 * 
 */
public class Worker {

    private static Worker _workerInstance = null;
    private WorkerThread _thread;
    private Vector _queue;

    /**
     * Creates a new <code>Worker</code> instance.
     */
    private Worker() {
        _queue = new Vector( 4 );
        _thread = new WorkerThread( _queue );
        _thread.start();
    }

    /**
     * Gets an instance of Worker Consider moving to RuntimeStore for making sure a singleton is achieved.
     */
    public static Worker getInstance() {
        if ( _workerInstance == null ) {
            _workerInstance = new Worker();
        }
        return _workerInstance;
    }

    /**
     * Add an element to the queue to be run.
     * 
     * @param runnable
     *            The {@link java.lang.Runnable} to run.
     */
    public void addToQueue( Runnable runnable ) {
        synchronized( _queue ) {
            checkIfRunning();
            _queue.addElement( runnable );
            _queue.notify();
        }
    }

    /**
     * Checks the thread and creates a new one if necessary.
     */
    private void checkIfRunning() {
        if ( !_thread.isAlive() ) {
            _thread = new WorkerThread( _queue );
            _thread.start();
        }
    }
}

final class WorkerThread extends Thread {

    private static final long THREAD_TIMEOUT = 10 * 1000L;

    private Vector _queue;

    WorkerThread( Vector queue ) {
        _queue = queue;
    }

    private boolean isEmpty() {
        return _queue.size() == 0;
    }

    public void run() {
        Runnable runnable = null;
        while( true ) {
            synchronized( _queue ) {
                while( isEmpty() ) {
                    try {
                        _queue.wait( THREAD_TIMEOUT );
                        if ( isEmpty() ) {
                            break;
                        }
                    } catch ( InterruptedException e ) {
                    }
                }
                if ( isEmpty() ) {
                    break;
                }
                runnable = (Runnable) _queue.elementAt( 0 );
                _queue.removeElementAt( 0 );
            }
            try {
                runnable.run();
            } catch ( Throwable e ) {
                // Log Exception
            }
            runnable = null;
        }
    }
}
